// 这是一个“通过通信来共享内存”的例子
package main

import "fmt"

func counterWorker(incChan chan int, resultChan chan int) {
	count := 0 // 状态是私有的，不共享
	for {
		// 通过通信来接收指令
		op, more := <-incChan
		if !more {
			// 通道关闭，发送最终结果
			resultChan <- count
			return
		}
		if op == 1 {
			count++ // 修改私有状态，无需加锁！
		}
	}
}

func main() {
	incChan := make(chan int)
	resultChan := make(chan int)

	// 启动工作协程
	go counterWorker(incChan, resultChan)

	// 发送1000次增加指令（通过通信）
	for i := 0; i < 1000; i++ {
		incChan <- 1
	}
	close(incChan) // 关闭通道，通知工作协程结束

	// 通过通信来获取最终结果
	finalCount := <-resultChan
	fmt.Println(finalCount) // 输出: 1000
}

/*
	通过“通信”的实现方式，通常是指用消息传递机制
	1. 通信的工具 - channel (其他预览的Actor模型[如Erlang,Akka]、消息队列MQ)
    2. 共享的内存: 数据被封装起来，其所有权通过channel传递，channel本身可以被看作是一个线程安全的队列
*/

/*
	在这个例子里：
		没有共享的 counter 变量。
		counterWorker 协程拥有自己私有的 count 状态。
		main 协程通过向 incChan 发送消息（<-1）来通信，告诉 counterWorker 该增加计数了。
		counterWorker 通过向 resultChan 发送消息来通信，告诉 main 最终的结果。
*/

// 如果需要共享数据，我们是通过传递它的所有权来实现的。
// 例如，我们可以通过 Channel 发送一个指针，但关键是，在任何一个时间点，只有一个协程拥有并可以安全地访问该指针指向的数据。
// 指针 --> 指向一块内存*(地址) ?

// 在Go中，channel是线程安全的，因此我们不需要加锁。 qa?

//“不要通过共享内存的方式进行通信”：不要依赖于让多个执行流去争抢同一块数据来隐式地交流，因为这会导致混乱和危险。
//“而应该通过通信来共享内存”：应该让执行流通过像 Channel 这样的安全管道来显式地传递消息和数据，从而实现安全、可控的“共享”。
/*

方面			通过共享内存通信								通过通信来共享内存
核心概念		隐式地通过修改共享状态来交流						显式地通过发送消息来交流
数据所有权	模糊，大家都能碰								清晰，一次只属于一个协程
同步机制		锁（Mutex）、信号量等（你手动管理）				Channel（同步内建于操作中）
代码风格		“你来拿”										“我发给你”
类比			一个共享的白板：谁拿到笔就可以去修改，其他人看。		传递纸条：我把写好的信息折起来递给你，只有你能看。
*/
